package hr.fer.zpr.nmbp.project3.dao;

import hr.fer.zpr.nmbp.project3.dao.exceptions.DAOException;
import hr.fer.zpr.nmbp.project3.dao.util.ObjectFromXMLGen;
import hr.fer.zpr.nmbp.project3.dao.util.XMLGen;
import hr.fer.zpr.nmbp.project3.model.Bolnica;
import hr.fer.zpr.nmbp.project3.model.Lijecnik;
import java.util.ArrayList;
import java.util.List;

import org.exist.xmldb.XQueryService;
import org.w3c.dom.Node;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.ResourceIterator;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;

public class LijecnikDAO {
    
	private XQueryService xqs;
	
    public LijecnikDAO(Collection col) {
    	try {
			this.xqs = (XQueryService)col.getService("XQueryService", "1.0");
		} catch (XMLDBException e) {
			throw new DAOException("Greška u radu s bazom");
		}
	}

	public void save(Lijecnik lijecnik) {    	
		// Update liječnika ako postoji u bazi
    	try {
			if(this.exists(lijecnik)) {
				this.update(lijecnik);
				return;
			}

	    	// Generiraj novu sifru ako ju nema
	    	if(lijecnik.getSifra() == 0){
	    		lijecnik.setSifra(this.generateNextSifra());
	    	}

    		// Spremanje novog liječnika u bazu
			xqs.query("update insert " + XMLGen.getXML(lijecnik) + "into /ebolnica/lijecnici");
		} catch (XMLDBException e) {
			throw new DAOException("Greška u radu s bazom!");
		}
    }
    
    private void update(Lijecnik lijecnik) {
		
		// Ažuriranje liječnika
    	try {
			xqs.query("update replace /ebolnica/lijecnici/lijecnik[@sifra=" + lijecnik.getSifra() + "] " +
					"with " + XMLGen.getXML(lijecnik));
		} catch (XMLDBException e) {
			throw new DAOException("Greška u radu s bazom!");
		}
	}

	private boolean exists(Lijecnik lijecnik) throws XMLDBException {
    	ResourceSet set = xqs.query("/ebolnica/lijecnici/lijecnik[@sifra="+lijecnik.getSifra()+"]");
    	if(set.getSize() > 0){
    		return true;
    	}else{
    		return false;
    	}
	}

	private int generateNextSifra() {
    	int nextSifra;
    	try {
    		ResourceSet resSet = xqs.query("let $res := /ebolnica/lijecnici/lijecnik/@sifra return" +
    				" <nextid>{ if (count($res) > 0) then max($res)+1 else 0+1 }</nextid>");
			Node node = (Node)((XMLResource)resSet.getIterator().nextResource()).getContentAsDOM();
			nextSifra = Integer.parseInt(node.getNodeValue());
		} catch (XMLDBException e) {
			throw new DAOException("Greška u radu s bazom!");
		}
    	
    	return nextSifra;
	}

	public void delete(Lijecnik lijecnik) {
    	try {
    		// Brisanje stranih ključeva
    		xqs.query("update replace /ebolnica/pacijenti/pacijent[@lijecnik=" + lijecnik.getSifra() + "]" +
    				"/@lijecnik with 0");
    		
    		// Brisanje liječnika
			xqs.query("update delete /ebolnica/lijecnici/lijecnik[@sifra=" + lijecnik.getSifra() + "]");
		} catch (XMLDBException e) {
			throw new DAOException("Greška u radu s bazom!");
		}
    }

    public List<Lijecnik> load(Lijecnik lijecnikPrototype) {
    	List<Lijecnik> allLijecnici = this.loadAll();
    	List<Lijecnik> filteredLijecnici = new ArrayList<Lijecnik>();
    	
    	for(Lijecnik lijecnik : allLijecnici){
    		if(lijecnik.getSifra() == lijecnikPrototype.getSifra()){
    			filteredLijecnici.add(lijecnik);
    		}
    	}
    	
    	return filteredLijecnici;
    }
    
    public List<Lijecnik> loadAll() {
    	ArrayList<Lijecnik> loadedLijecnici = new ArrayList<Lijecnik>();
    	
    	// Učitavanje liječnika
    	try {
    		ResourceSet resSet = xqs.query("/ebolnica/lijecnici/lijecnik");

    		ResourceIterator iter = resSet.getIterator();
			while(iter.hasMoreResources()){
				XMLResource res = (XMLResource) iter.nextResource();
				Lijecnik tempLijecnik = (Lijecnik)ObjectFromXMLGen.createInstance(res.getContentAsDOM());
				if(tempLijecnik != null){
					loadedLijecnici.add(tempLijecnik);
				}
			}
		} catch (XMLDBException e) {
			throw new DAOException("Greška u radu s bazom!");
		}
    	
    	return loadedLijecnici;
    }

    public List<Lijecnik> load(Bolnica bolnica){
    	List<Lijecnik> allLijecnici = this.loadAll();
    	List<Lijecnik> filteredLijecnici = new ArrayList<Lijecnik>();
    	
    	for(Lijecnik lijecnik : allLijecnici){
    		if(lijecnik.getSifra() != 0 && lijecnik.getBolnica() != null){
    			if(lijecnik.getBolnica().equals(bolnica)){
    				filteredLijecnici.add(lijecnik);
    			}
    		}
    	}
    	
    	return filteredLijecnici;
    }
}
